package org.liveboardgames.agricola.business.helper;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.liveboardgames.agricola.domain.Game;
import org.liveboardgames.agricola.domain.action.Action;
import org.liveboardgames.agricola.domain.board.BoardTile;
import org.liveboardgames.agricola.domain.card.ActionCard;
import org.liveboardgames.agricola.domain.card.Card;
import org.liveboardgames.agricola.domain.card.ImprovementCard;
import org.liveboardgames.agricola.domain.common.IResourceContainer;
import org.liveboardgames.agricola.domain.common.Peep;
import org.liveboardgames.agricola.domain.farm.Farm;
import org.liveboardgames.agricola.domain.farm.FarmTile;
import org.liveboardgames.agricola.domain.farm.Pasture;
import org.liveboardgames.agricola.domain.player.Player;
import org.liveboardgames.agricola.model.enums.ActionTempoEnum;
import org.liveboardgames.agricola.model.enums.BoardTileTypeEnum;
import org.liveboardgames.agricola.model.enums.DirectionEnum;
import org.liveboardgames.agricola.model.enums.FarmElementEnum;
import org.liveboardgames.agricola.model.enums.HarvestStepEnum;
import org.liveboardgames.agricola.model.enums.HouseTypeEnum;
import org.liveboardgames.agricola.model.enums.ImprovementTypeEnum;
import org.liveboardgames.agricola.model.enums.ResourceTypeEnum;
import org.liveboardgames.agricola.model.enums.RoundOffsetTypeEnum;

public class GameHelper {

  private static final int MAX_FENCES = 15;

  public static final int NUMBER_OF_TURNS = 14;

  public static final Set<Integer> HARVEST_ROUNDS = getHarvestRounds();

  private static Set<Integer> getHarvestRounds() {
    Set<Integer> harvestRounds = new HashSet<Integer>();

    harvestRounds.add(4);
    harvestRounds.add(7);
    harvestRounds.add(9);
    harvestRounds.add(11);
    harvestRounds.add(13);
    harvestRounds.add(14);

    return harvestRounds;
  }

  public List<Card> getAllPlayedCards(Game game) {
    List<Card> playedCards = new ArrayList<Card>();

    // Get the cards that have been played on the board
    List<BoardTile> tiles = game.getTiles();
    for (Iterator<BoardTile> iterator = tiles.iterator(); iterator.hasNext();) {
      BoardTile boardTile = iterator.next();
      ActionCard actionCard = boardTile.getActionCard();
      if (actionCard != null) {
        playedCards.add(actionCard);
      }
    }

    // Get the cards that have been played by each player
    List<Player> players = game.getPlayers();
    for (Iterator<Player> iterator = players.iterator(); iterator.hasNext();) {
      Player player = iterator.next();
      Set<Card> playerCards = player.getFarm().getPlayedCards();
      if (playerCards != null) {
        for (Iterator<Card> iterator2 = playerCards.iterator(); iterator2.hasNext();) {
          Card card = iterator2.next();
          playedCards.add(card);
        }
      }
    }

    return playedCards;
  }

  public Player getPeepOwner(Game game, Peep peep) {
    Player owner = null;

    List<Player> players = game.getPlayers();
    for (Player player : players) {
      if (player.getPeeps().contains(peep)) {
        owner = player;
        break;
      }
    }

    return owner;
  }

  public List<Peep> getPeepsOnFarm(Farm farm) {
    List<Peep> peeps = new ArrayList<Peep>();

    List<FarmTile> tiles = farm.getTiles();
    for (FarmTile farmTile : tiles) {
      Set<Peep> peepsOnTile = farmTile.getPeeps();
      if (peepsOnTile != null) {
        for (Peep peep : peepsOnTile) {
          peeps.add(peep);
        }
      }
    }

    return peeps;
  }

  public BoardTile findFirstEmptySeasonTile(Game game) {
    BoardTile firstEmptySeasonTile = null;

    List<BoardTile> tiles = game.getTiles();
    for (BoardTile boardTile : tiles) {
      if (BoardTileTypeEnum.SEASON.equals(boardTile.getType()) && boardTile.getActionCard() == null) {
        firstEmptySeasonTile = boardTile;
        break;
      }
    }

    return firstEmptySeasonTile;
  }

  public List<Action> getAllStartOfRoundActions(Game game) {
    List<Action> startActions = new ArrayList<Action>();

    // Retrieve all the cards that have been put in play
    List<Card> playedCards = getAllPlayedCards(game);

    for (Card card : playedCards) {
      Set<Action> actions = card.getActions();
      if (actions != null) {
        for (Action action : actions) {
          if (ActionTempoEnum.START_OF_ROUND.equals(action.getTempo())) {
            startActions.add(action);
          }
        }
      }
    }

    return startActions;
  }

  public FarmTile getFarmTileContainingPeep(Game game, Peep peep) {
    FarmTile farmTile = null;

    if (peep != null) {
      Farm farm = getPeepOwner(game, peep).getFarm();
      for (FarmTile tile : farm.getTiles()) {
        if (tile.getPeeps() != null && tile.getPeeps().contains(peep)) {
          farmTile = tile;
          break;
        }
      }
    }

    return farmTile;
  }

  public Card findCard(Game game, Long cardId) {
    Card result = null;

    List<Card> playedCards = getAllPlayedCards(game);
    for (Card card : playedCards) {
      if (card.getCardId().equals(cardId)) {
        result = card;
      }
    }

    return result;
  }

  public ImprovementCard findMajorImprovement(Game game, Long improvementId) {
    ImprovementCard result = null;

    Set<ImprovementCard> majorImprovements = game.getMajorImprovements();
    for (ImprovementCard card : majorImprovements) {
      if (card.getCardId().equals(improvementId)) {
        result = card;
      }
    }

    return result;
  }

  public Peep findPeep(Game game, Long peepId) {
    Peep result = null;

    List<Player> players = game.getPlayers();
    for (Player player : players) {
      for (Peep peep : player.getPeeps()) {
        if (peep.getId().equals(peepId)) {
          result = peep;
        }
      }
    }

    return result;
  }

  public int getNumberOfRooms(Farm farm) {
    int numberOfElements = 0;

    for (FarmTile tile : farm.getTiles()) {
      if (FarmElementEnum.isRoom(tile.getFarmElement())) {
        numberOfElements++;
      }
    }

    return numberOfElements;
  }

  public Action findAction(Game game, Long actionId) {
    Action result = null;

    List<Card> playedCards = getAllPlayedCards(game);

    for (Card card : playedCards) {
      Set<Action> actions = card.getActions();
      if (actions != null) {
        for (Action action : actions) {
          if (actionId.equals(action.getId())) {
            result = action;
            break;
          }
        }
      }
    }

    return result;
  }

  public BoardTile findBoardTile(Game game, Long targetId) {
    BoardTile result = null;

    for (BoardTile tile : game.getTiles()) {
      if (tile.getUniqueId().equals(targetId)) {
        result = tile;
      }
    }

    return result;
  }

  public Player findPlayer(Game game, Long targetId) {
    Player result = null;

    for (Player player : game.getPlayers()) {
      if (player.getId().equals(targetId)) {
        result = player;
      }
    }

    return result;
  }

  public Farm findFarm(Game game, Long targetId) {
    Farm result = null;

    for (Player player : game.getPlayers()) {
      if (player.getFarm().getId().equals(targetId)) {
        result = player.getFarm();
      }
    }

    return result;
  }

  public FarmTile findFarmTile(Game game, Long targetId) {
    FarmTile result = null;

    List<Player> players = game.getPlayers();
    for (Iterator<Player> iterator = players.iterator(); iterator.hasNext() && result == null;) {
      Player player = iterator.next();
      Farm farm = player.getFarm();
      result = findFarmTile(farm, targetId);
    }

    return result;
  }

  public FarmTile findFarmTile(Farm farm, Long targetId) {
    FarmTile result = null;
    for (FarmTile tile : farm.getTiles()) {
      if (tile.getUniqueId().equals(targetId)) {
        result = tile;
        break;
      }
    }
    return result;
  }

  public IResourceContainer findResourceContainer(Game game, Long targetId, String targetType) {
    IResourceContainer host = null;

    if (targetType.equals("Farm")) {
      host = findFarm(game, targetId);
    }
    else if (targetType.equals("FarmTile")) {
      host = findFarmTile(game, targetId);
    }
    else if (targetType.equals("Card")) {
      host = findCard(game, targetId);
    }

    return host;
  }

  public Set<FarmTile> findFarmTiles(Farm farm, Set<Integer> tileIds) {
    Set<FarmTile> farmTiles = new HashSet<FarmTile>();

    for (Integer tileId : tileIds) {
      FarmTile farmTile = findFarmTile(farm, new Long(tileId));
      farmTiles.add(farmTile);
    }

    return farmTiles;
  }

  public Set<Long> getNewFences(Farm farm, Set<FarmTile> pastureTiles) {
    // Retrieve the fences that are already built on the farm
    Set<Long> alreadyBuiltFences = getBuiltFencesIds(farm);

    // Retrieve the fences that would be needed to enclose the pasture
    // (including the ones already present)
    Set<Long> necessaryFencesForPasture = getPastureFenceIds(farm, pastureTiles);

    // From there, compute the ids of fences that are yet to be built
    Set<Long> newFences = new HashSet<Long>();
    for (Long fenceId : necessaryFencesForPasture) {
      if (!alreadyBuiltFences.contains(fenceId)) {
        newFences.add(fenceId);
      }
    }

    return newFences;
  }

  /**
   * The total number of fences needed by a set of tiles for a single pasture
   */
  private Set<Long> getPastureFenceIds(Farm farm, Set<FarmTile> pastureTiles) {
    Set<Long> fenceIDs = new HashSet<Long>();

    Set<FarmTile> countedTiles = new HashSet<FarmTile>();

    // Iterate on each of the tile of the farm
    for (FarmTile tile : pastureTiles) {
      // In this case, check each of the fences
      Long id = tile.getId();

      // 1. Left fence
      Long leftFenceID = getFenceID(tile, DirectionEnum.LEFT);
      // If the tile is on the left (and belongs to a pasture), this means that
      // there must
      // be a fence on the left
      if (id < 3) {
        fenceIDs.add(leftFenceID);
      }
      // Otherwise, if the field on the left is in another pasture
      // (and has not been dealt with yet), there is a fence
      else {
        FarmTile leftTile = farm.getTileAt(id - 3);
        if (!pastureTiles.contains(leftTile)) {
          fenceIDs.add(leftFenceID);
        }
      }

      // 2. Right fence
      Long rightFenceID = getFenceID(tile, DirectionEnum.RIGHT);
      // If the tile is on the right (and belongs to a pasture), this means that
      // there must
      // be a fence on the right
      if (id > 11) {
        fenceIDs.add(rightFenceID);
      }
      // Otherwise, if the field on the right is in another pasture
      // (and has not been dealt with yet), there is a fence
      else {
        FarmTile rightTile = farm.getTileAt(id + 3);
        if (!pastureTiles.contains(rightTile)) {
          fenceIDs.add(rightFenceID);
        }
      }

      // 3. Top fence
      Long topFenceID = getFenceID(tile, DirectionEnum.TOP);
      // If the tile is on the top (and belongs to a pasture), this means that
      // there must
      // be a fence on the top
      if ((id % 3) == 2) {
        fenceIDs.add(topFenceID);
      }
      // Otherwise, if the field on the top is in another pasture
      // (and has not been dealt with yet), there is a fence
      else {
        FarmTile topTile = farm.getTileAt(id + 1);
        if (!pastureTiles.contains(topTile)) {
          fenceIDs.add(topFenceID);
        }
      }

      // 4. Bottom fence
      Long bottomFenceID = getFenceID(tile, DirectionEnum.BOTTOM);
      // If the tile is at the bottom (and belongs to a pasture), this means
      // that there must
      // be a fence at the bottom
      if ((id % 3) == 0) {
        fenceIDs.add(bottomFenceID);
      }
      // Otherwise, if the field at the bottom is in another pasture
      // (and has not been dealt with yet), there is a fence
      else {
        FarmTile bottomTile = farm.getTileAt(id - 1);
        if (!pastureTiles.contains(bottomTile)) {
          fenceIDs.add(bottomFenceID);
        }
      }

      countedTiles.add(tile);
    }

    return fenceIDs;
  }

  /** Get the whole list of fences for the farm. */
  private Set<Long> getBuiltFencesIds(Farm farm) {
    Set<Long> fenceIDs = new HashSet<Long>();

    Set<FarmTile> countedTiles = new HashSet<FarmTile>();

    // Iterate on each of the tile of the farm
    for (FarmTile tile : farm.getTiles()) {
      // Only the ones that belong to a pasture are of interest
      Pasture currentPasture = tile.getPasture();

      if (currentPasture == null) {
        continue;
      }

      // In this case, check each of the fences
      // Please note that we use the ID (and not the unique ID), since there is
      // a direct correlation of the ID (identifier within the farm) and the
      // position of the tile
      Long id = tile.getId();

      // 1. Left fence
      Long leftFenceID = getFenceID(tile, DirectionEnum.LEFT);
      // If the tile is on the left (and belongs to a pasture), this means that
      // there must be a fence on the left
      if (id < 3) {
        fenceIDs.add(leftFenceID);
      }
      // Otherwise, if the field on the left is in another pasture (and has not
      // been dealt with yet), there is a fence
      else {
        FarmTile leftTile = farm.getTileAt(id - 3);
        Pasture leftPasture = leftTile.getPasture();

        if (!countedTiles.contains(leftTile) && !currentPasture.equals(leftPasture)) {
          fenceIDs.add(leftFenceID);
        }
      }

      // 2. Right fence
      Long rightFenceID = getFenceID(tile, DirectionEnum.RIGHT);
      // If the tile is on the right (and belongs to a pasture), this means that
      // there must
      // be a fence on the right
      if (id > 11) {
        fenceIDs.add(rightFenceID);
      }
      // Otherwise, if the field on the right is in another pasture
      // (and has not been dealt with yet), there is a fence
      else {
        FarmTile rightTile = farm.getTileAt(id + 3);
        Pasture rightPasture = rightTile.getPasture();

        if (!countedTiles.contains(rightTile) && !currentPasture.equals(rightPasture)) {
          fenceIDs.add(rightFenceID);
        }
      }

      // 3. Top fence
      Long topFenceID = getFenceID(tile, DirectionEnum.TOP);
      // If the tile is on the top (and belongs to a pasture), this means that
      // there must
      // be a fence on the top
      if ((id % 3) == 2) {
        fenceIDs.add(topFenceID);
      }
      // Otherwise, if the field on the top is in another pasture
      // (and has not been dealt with yet), there is a fence
      else {
        FarmTile topTile = farm.getTileAt(id + 1);
        Pasture topPasture = topTile.getPasture();

        if (!countedTiles.contains(topTile) && !currentPasture.equals(topPasture)) {
          fenceIDs.add(topFenceID);
        }
      }

      // 4. Bottom fence
      Long bottomFenceID = getFenceID(tile, DirectionEnum.BOTTOM);
      // If the tile is at the bottom (and belongs to a pasture), this means
      // that there must
      // be a fence at the bottom
      if ((id % 3) == 0) {
        fenceIDs.add(bottomFenceID);
      }
      // Otherwise, if the field at the bottom is in another pasture
      // (and has not been dealt with yet), there is a fence
      else {
        FarmTile bottomTile = farm.getTileAt(id - 1);
        Pasture bottomPasture = bottomTile.getPasture();

        if (!countedTiles.contains(bottomTile) && !currentPasture.equals(bottomPasture)) {
          fenceIDs.add(bottomFenceID);
        }
      }

      countedTiles.add(tile);
    }

    return fenceIDs;
  }

  /**
   * Fences are ordered: first horizontal, then vertical. Tiles with ID from 0
   * to 19 are horizontal tiles (from bottom to top, then left to right). Tiles
   * with ID form 20 to 37 are vertical tiles (from bottom to top, then left to
   * right)
   */
  private Long getFenceID(FarmTile tile, DirectionEnum direction) {
    double fenceID = 0;
    Long n = tile.getId();

    switch (direction) {
      case BOTTOM:
        fenceID = 4 * Math.floor(n / 3) + (n % 3);
        break;
      case TOP:
        fenceID = 4 * Math.floor(n / 3) + (n % 3) + 1;
        break;
      case LEFT:
        fenceID = 20 + n;
        break;
      case RIGHT:
        fenceID = 20 + 3 + n;
        break;
    }

    return Double.valueOf(fenceID).longValue();
  }

  public Integer computeAvailableFences(Farm farm) {
    Integer remainingFences = getRemainingFences(farm);
    Integer remainingWoods = farm.getResources().get(ResourceTypeEnum.WOOD);

    return Math.min(remainingFences, remainingWoods);
  }

  private Integer getRemainingFences(Farm farm) {
    Set<Long> builtFences = getBuiltFencesIds(farm);
    Integer remainingWoods = farm.getResources().get(ResourceTypeEnum.WOOD);

    return Math.min(MAX_FENCES - builtFences.size(), remainingWoods);
  }

  public ImprovementCard findFireplace(Farm farm) {
    ImprovementCard result = null;

    Set<Card> playedCards = farm.getPlayedCards();
    if (playedCards != null) {
      for (Card card : playedCards) {
        if (card instanceof ImprovementCard) {
          ImprovementCard improvement = (ImprovementCard)card;
          if (improvement.getTypes() != null && improvement.getTypes().contains(ImprovementTypeEnum.FIREPLACE)) {
            result = improvement;
          }
        }
      }
    }

    return result;
  }

  public Set<Action> getPlayTriggeredActions(ImprovementCard improvement) {
    Set<Action> result = null;

    if (improvement != null) {
      result = new HashSet<Action>();
      Set<Action> actions = improvement.getActions();
      if (actions != null) {
        for (Action action : actions) {
          if (ActionTempoEnum.PLAY_TRIGGERED.equalsIgnoreCase(action.getTempo())) {
            result.add(action);
          }
        }
      }
    }

    return result;
  }

  public BoardTile getTileForRound(Game game, Integer round) {
    BoardTile boardTile = game.getTiles().get(round - 1 + 16);
    return boardTile;
  }

  public int getCurrentRoundNumber(Game game) {
    int turnsToPlay = game.getWaitingActionCards().size();
    int currentRoundNumber = NUMBER_OF_TURNS - turnsToPlay;
    return currentRoundNumber;
  }

  public Set<Integer> computeRealRoundNumbers(Game game, Set<Integer> roundNumbers, String offsetType) {
    Set<Integer> realRoundNumbers = new HashSet<Integer>();

    // If the round number are absolute, nothing to do
    if (RoundOffsetTypeEnum.ROUND_NUMBER.equalsIgnoreCase(offsetType)) {
      realRoundNumbers = roundNumbers;
    }
    // Else we need to get the absolute value of these rounds
    else if (RoundOffsetTypeEnum.ADD.equalsIgnoreCase(offsetType)) {
      int currentRound = getCurrentRoundNumber(game);
      for (Integer roundNumber : roundNumbers) {
        Integer newRoundNumber = roundNumber + currentRound;
        if (newRoundNumber <= GameHelper.NUMBER_OF_TURNS) {
          realRoundNumbers.add(newRoundNumber);
        }
      }
    }

    return realRoundNumbers;
  }

  public Player findNextPlayerToPlay(Game game) {
    Player nextPlayer = null;

    // Is there still a player who has peeps to play?
    boolean haveAllPlayersPlayed = haveAllPlayersPlayed(game);
    if (!haveAllPlayersPlayed) {
      // The player who is currently playing
      Player player = game.getCurrentPlayer();

      // If no one is currently playing, the first player
      // in the list will be the next one to have their turn.
      List<Player> players = game.getPlayers();
      if (player == null) {
        nextPlayer = players.get(0);
      }
      // Else, we get the next player in the list who has a
      // peep to play
      else {
        // The position of the current player in the list
        int currentPosition = players.indexOf(player);

        // iterate over all the players of the game until we find
        // one who could play
        int numberOfIterations = 0;
        while (numberOfIterations++ < players.size()) {
          // The next player can be the first one, if the current player
          // is the last one of the list
          int nextPlayerIndex = (++currentPosition % players.size());

          // Does this player still have a peep to play?
          Player potentialNextPlayer = players.get(nextPlayerIndex);
          List<Peep> peeps = getPeepsOnFarm(potentialNextPlayer.getFarm());
          if (peeps != null && peeps.size() > 0) {
            nextPlayer = potentialNextPlayer;
            break;
          }
        }
      }
    }
    return nextPlayer;
  }

  private boolean haveAllPlayersPlayed(Game game) {
    boolean result = true;
    List<Player> players = game.getPlayers();
    for (Player player : players) {
      boolean hasPlayedAllPeeps = hasPlayedAllPeeps(player);
      result = result && hasPlayedAllPeeps;
    }
    return result;
  }

  private boolean hasPlayedAllPeeps(Player player) {
    boolean result = false;
    List<Peep> peepsOnFarm = getPeepsOnFarm(player.getFarm());
    if (peepsOnFarm == null || peepsOnFarm.size() == 0) {
      result = true;
    }
    return result;
  }

  public boolean isHarvest(Game game) {
    boolean isHarvest = false;

    List<ActionCard> waitingActions = game.getWaitingActionCards();
    Integer currentRound = NUMBER_OF_TURNS - waitingActions.size();
    if (HARVEST_ROUNDS.contains(currentRound)) {
      isHarvest = true;
    }

    return isHarvest;
  }

  public Player findNextPlayerToHarvest(Game game) {
    Player nextPlayer = null;

    // The first player to harvest is the first player of the turn
    List<Player> players = game.getPlayers();

    for (Player player : players) {
      if (!player.isHasHarvested()) {
        nextPlayer = player;
        break;
      }
    }

    return nextPlayer;
  }

  public Player getHarvestingPlayer(Game game, String harvestStep) {
    Player harvestingPlayer = null;

    // Iterate in the order of the turn
    for (Player player : game.getPlayers()) {
      Set<Player> playerList = getPlayerListFromHarvestStep(game, harvestStep);
      if (!playerList.contains(player)) {
        harvestingPlayer = player;
        break;
      }
    }

    return harvestingPlayer;
  }

  private Set<Player> getPlayerListFromHarvestStep(Game game, String harvestStep) {
    Set<Player> result = null;

    if (HarvestStepEnum.FIELD.equalsIgnoreCase(harvestStep)) {
      result = game.getHarvestFieldPlayers();
    }
    else if (HarvestStepEnum.FEED.equalsIgnoreCase(harvestStep)) {
      result = game.getHarvestFeedPlayers();
    }
    else if (HarvestStepEnum.BREED.equalsIgnoreCase(harvestStep)) {
      result = game.getHarvestBreedPlayers();
    }

    return result;
  }

  public String findNextHarvestStep(Game game) {
    String currentStep = null;

    if (game.getHarvestFieldPlayers().size() != game.getPlayers().size()) {
      currentStep = HarvestStepEnum.FIELD;
    }
    else if (game.getHarvestFeedPlayers().size() != game.getPlayers().size()) {
      currentStep = HarvestStepEnum.FEED;
    }
    else if (game.getHarvestBreedPlayers().size() != game.getPlayers().size()) {
      currentStep = HarvestStepEnum.BREED;
    }

    return currentStep;
  }

  public boolean isGameFinished(Game game) {
    int currentRound = getCurrentRoundNumber(game);
    boolean isGameFinished = (currentRound == NUMBER_OF_TURNS);
    return isGameFinished;
  }

  public int getNumberOfFields(Farm farm) {
    int numberOfFields = 0;
    List<FarmTile> tiles = farm.getTiles();
    for (FarmTile farmTile : tiles) {
      String farmElement = farmTile.getFarmElement();
      if (FarmElementEnum.FIELD.equalsIgnoreCase(farmElement)) {
        numberOfFields++;
      }
    }
    return numberOfFields;
  }

  public int getNumberOfPastures(Farm farm) {
    Set<Pasture> pastures = new HashSet<Pasture>();
    List<FarmTile> tiles = farm.getTiles();
    for (FarmTile farmTile : tiles) {
      Pasture pasture = farmTile.getPasture();
      if (!pastures.contains(pasture)) {
        pastures.add(pasture);
      }
    }
    return pastures.size();
  }

  public int getNumberOfGrains(Farm farm) {
    return farm.getResourceQuantity(ResourceTypeEnum.GRAIN);
  }

  public int getNumberOfVegetables(Farm farm) {
    return farm.getResourceQuantity(ResourceTypeEnum.VEGETABLE);
  }

  public int getNumberOfSheep(Farm farm) {
    return farm.getResourceQuantity(ResourceTypeEnum.SHEEP);
  }

  public int getNumberOfBoar(Farm farm) {
    return farm.getResourceQuantity(ResourceTypeEnum.BOAR);
  }

  public int getNumberOfCattle(Farm farm) {
    return farm.getResourceQuantity(ResourceTypeEnum.CATTLE);
  }

  public int getNumberOfFreeSpaces(Farm farm) {
    int numberOfElements = 0;
    List<FarmTile> tiles = farm.getTiles();
    for (FarmTile farmTile : tiles) {
      if (farmTile.isFree()) {
        numberOfElements++;
      }
    }
    return numberOfElements;
  }

  public int getNumberOfFencedStables(Farm farm) {
    int numberOfElements = 0;
    List<FarmTile> tiles = farm.getTiles();
    for (FarmTile farmTile : tiles) {
      if (FarmElementEnum.STABLE.equals(farmTile.getFarmElement()) && farmTile.getPasture() != null) {
        numberOfElements++;
      }
    }
    return numberOfElements;
  }

  public int getNumberOfClayRooms(Farm farm) {
    int numberOfElements = 0;
    String houseType = getHouseType(farm);
    if (HouseTypeEnum.CLAY.equalsIgnoreCase(houseType)) {
      numberOfElements = getNumberOfRooms(farm);
    }
    return numberOfElements;
  }

  public int getNumberOfStoneRooms(Farm farm) {
    int numberOfElements = 0;
    String houseType = getHouseType(farm);
    if (HouseTypeEnum.STONE.equalsIgnoreCase(houseType)) {
      numberOfElements = getNumberOfRooms(farm);
    }
    return numberOfElements;
  }

  private String getHouseType(Farm farm) {
    String room = farm.getTiles().get(0).getFarmElement();
    String houseMaterial = FarmElementEnum.getRoomMaterial(room);
    return houseMaterial;
  }

  public int getNumberOfFamilyMembers(Player player) {
    return player.getPeeps().size();
  }
}